///////////////////////////////////////////////////////////////////////////////
//
// lighthouse3D - 3D Software Library
//
// File: CTGAFileHandler.cpp
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2013 Marcus Reinhardt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
//
// You can find a copy of the GNU General Public License (gpl.txt) in the
// directory of the library.
//
///////////////////////////////////////////////////////////////////////////////
#include "CTGAFileHandler.h"

///////////////////////////////////////////////////////////////////////////////
// CTGAFileHandler::CTGAFileHandler( ... )
///////////////////////////////////////////////////////////////////////////////
CTGAFileHandler::CTGAFileHandler()
{
}

///////////////////////////////////////////////////////////////////////////////
// CTGAFileHandler::~CTGAFileHandler( ... )
///////////////////////////////////////////////////////////////////////////////
CTGAFileHandler::~CTGAFileHandler()
{
}

///////////////////////////////////////////////////////////////////////////////
// CTGAFileHandler::loadTGAFile()( ... )
///////////////////////////////////////////////////////////////////////////////
// Loads a TGA File
//
// Limitations
// * Only 24 BPP
///////////////////////////////////////////////////////////////////////////////
bool CTGAFileHandler::loadTGAFile(const char *fname)
{
  FILE *f;
  unsigned int counter;
  unsigned int imageType, imageWidth, imageHeight, imageBPP, imageSize, imageCMP;
  unsigned char buffer1, buffer2;
  char dataBuffer[1024];


  TTGAHeader TGAHeader;
  
  f = fopen(fname, "rb");

  if( f == NULL )
  {
     return false;
  }

  // Try to read the header of the TGA file
  if( fread(&TGAHeader, sizeof(TTGAHeader), 1, f) == 0 )
  {
     if(f != NULL)
	 {
		fclose(f);
     }
     
     return false;
  }

  // Retreiving some facts from TGAHeader
  imageType	= TGAHeader.imageType;
  imageCMP	= TGAHeader.colorMapType;
  imageWidth = TGAHeader.widthLo + TGAHeader.widthHi * 256;
  imageHeight = TGAHeader.heightLo + TGAHeader.heightHi * 256;
  imageBPP = TGAHeader.BPP / 8;
  imageSize	= imageWidth * imageHeight * imageBPP;

  // Validate header info
  // (1) Uncompressed or rle compressed true color picture
  // (2) Width/Height not 0
  // (3) Width/Height not bigger than TPictureData maxima
  // (4) 24 bit picture
  if ( ( ( imageType != 2 ) && ( imageType != 10 ) ) ||
       ( imageWidth == 0 ) || ( imageHeight == 0 ) ||
       ( imageWidth >= _maxPicSizeX_ ) || ( imageHeight >= _maxPicSizeY_ ) ||
       ( imageBPP != 3) ||
	   ( imageCMP == 1) )
  {
	  fclose(f);
	  return false;
  }

  // Skip image ident field
  if( TGAHeader.imageId > 0 )
  {
	fseek(f, TGAHeader.imageId, SEEK_CUR);
  }

  picData.sizeX = imageWidth;
  picData.sizeY = imageHeight;

  // Load an uncompresses TGA image
  if ( imageType == 2 )
  {
 	  if( fread(&picData.raw, 1, imageSize, f) != imageSize )
	  {
         fclose(f);
         
         return false;
      }
  }
  else
  {
	  counter = 0;

      while (counter < imageWidth*imageHeight -1)
      {
         fread( &buffer1, 1, 1, f);

  	     // Check if next packet is rle encoded
         if ((buffer1 & 128) == 128)
         {   
		     // how many pixel in this packet?
             buffer2 = (buffer1 & 127) + 1;

             fread( &dataBuffer, 1, imageBPP, f);

             for(unsigned int i=counter; i<counter+(unsigned int)buffer2; i++)
                 for(unsigned int j=0; j<imageBPP; j++)
                     picData.raw[i*imageBPP+j] = dataBuffer[j];

             counter += buffer2;
          }
		  // or if is a raw packet
          else
          {   
             buffer2 = (buffer1 & 127) + 1;
			 if (imageBPP*buffer2 > 1024)
				 return false;

			 fread( &dataBuffer, 1, imageBPP*buffer2, f );

             for(unsigned int i=counter; i<counter+(unsigned int)buffer2; i++)
                 for(unsigned int j=0; j<imageBPP; j++)
                     picData.raw[i*imageBPP+j] = 
					         dataBuffer[(i-counter)*imageBPP+j];

             counter += buffer2;
          }
      }
  }

  // Convert the data from bgr to rgb
  counter = 0;
  for(int i = 0; i < (int)imageSize; i += imageBPP)
  {
      picData.rgb[counter] = picData.raw[i+2] + picData.raw[i+1]*256 + picData.raw[i]*256*256;
      counter++;
  }

  fclose(f);

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CTGAFileHandler::getRGBColor( ... )
///////////////////////////////////////////////////////////////////////////////
TRGBColorTriple CTGAFileHandler::getRGBColor(unsigned int c)
{
  TRGBColorTriple tRGB;

  tRGB.r = (unsigned int) (c & 0xFF);
  tRGB.g = (unsigned int) ((c>>8) & 0xFF);
  tRGB.b = (unsigned int) ((c>>16) & 0xFF);

  return tRGB;
}

///////////////////////////////////////////////////////////////////////////////
// CTGAFileHandler::saveTGAFile()( ... )
///////////////////////////////////////////////////////////////////////////////
// Saves a TGA File
///////////////////////////////////////////////////////////////////////////////
bool CTGAFileHandler::saveTGAFile(const char *fname, TPictureData *p)
{
  TTGAHeader TGAHeader;
  FILE *f;
  unsigned int imageWidth, imageHeight, imageBPP, imageSize, w, h, counter;

  // Setup tga header
  // No Identification Field
  TGAHeader.imageId = 0;
  TGAHeader.colorMapType = 0;
  // Uncompressed RGB image
  TGAHeader.imageType = 2;
  w = p->sizeX / 256;
  h = p->sizeY / 256;
  TGAHeader.widthLo = p->sizeX - w*256;
  TGAHeader.widthHi = w;
  TGAHeader.heightLo = p->sizeY - h*256;
  TGAHeader.heightHi = h;
  // 24 bit image
  TGAHeader.BPP = 24;
  // No alpha channels supported
  TGAHeader.descriptor = 0;

  // Retrieve image information again
  imageBPP = TGAHeader.BPP / 8;
  imageWidth = TGAHeader.widthLo + TGAHeader.widthHi * 256;
  imageHeight = TGAHeader.heightLo + TGAHeader.heightHi * 256;
  imageSize	= imageWidth * imageHeight * imageBPP;

  f = fopen(fname, "wb");

  if( f == NULL )
  {
     return false;
  }

  // Write tga picture header
  fwrite(&TGAHeader, sizeof(TTGAHeader), 1, f);

  // Convert the data from bgr to rgb
  counter = 0;
  for(int i = 0; i < (int)imageSize; i += imageBPP)
  {
	  p->raw[i+2] = getRGBColor(p->rgb[counter]).r;
	  p->raw[i+1] = getRGBColor(p->rgb[counter]).g;
	  p->raw[i+0] = getRGBColor(p->rgb[counter]).b;

	  counter++;
  }

  // Write tga picture data
  fwrite(&p->raw, imageSize, 1,f);
  
  fclose(f);

  return true;
}
